#include "VSMaterialPass.h"
#include "VSSpatial.h"
#include "VSBoneNode.h"
#include "VSShaderStringFactory.h"
#include "VSConstValue.h"
#include "VSGeometry.h"
#include "VSBoneNode.h"
#include "VSResourceManager.h"
#include "VSGraphicInclude.h"
#include "VSMaterial.h"
using namespace VSEngine2;
IMPLEMENT_RTTI(VSMaterialPass,VSPass)
static bool gs_bStreamRegistered_VSMaterialPass= VSMaterialPass::RegisterMainFactory();
bool VSMaterialPass::ms_bRegisterMainFactory = false;
bool VSMaterialPass::RegisterMainFactory()
{
	if (!ms_bRegisterMainFactory)
	{ 
		VSMain::AddInitialFuntion(VSMaterialPass::InitialClassFactory); 
		ms_bRegisterMainFactory = true;
	} 
	return ms_bRegisterMainFactory;

}
bool VSMaterialPass::InitialClassFactory()
{
	ms_ClassFactory.AddElement(ms_Type.GetName(),FactoryFunc);

	return 1;
}
VSObject * VSMaterialPass::FactoryFunc()
{
	return VS_NEW VSMaterialPass;

}
VSMaterialPass::VSMaterialPass()
{

	
	m_pMaterialInstance = NULL;
	m_pVShaderSet = NULL;
	m_pPShaderSet = NULL;
}
VSMaterialPass::~VSMaterialPass()
{

	m_pMaterialInstance = NULL;
	m_pVShaderSet = NULL;
	m_pPShaderSet = NULL;
}
bool VSMaterialPass::Draw(VSRenderer * pRenderer)
{
	if(!pRenderer || !m_pCamera || !m_pSpatial || !m_pMaterialInstance)
	{
		m_Light.Clear();
		return 0;
	}
	if (!GetVShader())
	{
		m_Light.Clear();
		return 0;
	}
	if (!GetPShader())
	{
		m_Light.Clear();
		return 0;
	}
	
	MaterialShaderPara1 MSPara1;
	MSPara1.pCamera = m_pCamera;
	MSPara1.pGeometry = (VSGeometry *)m_pSpatial;
	MSPara1.LightArray = m_Light;
	MSPara1.pMaterialInstance = m_pMaterialInstance;
	MSPara1.uiPassId = m_uiPassId;
	pRenderer->SetMaterialVShaderConstant(MSPara1,GetPassType(),m_pMaterialInstance->m_pCurVShader[GetPassType()]);
	pRenderer->SetMaterialPShaderConstant(MSPara1,GetPassType(),m_pMaterialInstance->m_pCurPShader[GetPassType()]);

	m_Light.Clear();

	VSMaterial * pMaterial = m_pMaterialInstance->GetMaterial();
	
	if(!pRenderer->DrawMesh((VSGeometry *)m_pSpatial,&pMaterial->GetRenderState(m_uiPassId),
		m_pMaterialInstance->m_pCurVShader[GetPassType()],
		m_pMaterialInstance->m_pCurPShader[GetPassType()]))
	{
		return false;
	}
	return 1;
}
bool VSMaterialPass::GetVShader()
{
	VSMaterial * pMaterial = m_pMaterialInstance->GetMaterial();
	if (!pMaterial)
	{
		return 0;
	}
	VSVShader * pVertexShader = NULL;
	
	unsigned int uiVShaderNum = 0;
	if (!m_pVShaderSet)
	{
		m_pVShaderSet = VSResourceManager::GetVertexShaderMap().GetShaderSet(VSUsedName::ms_cMaterialVertex);
	}
	else
	{
		uiVShaderNum = m_pVShaderSet->GetNum();
	}
	MaterialShaderPara1 MSPara1;
	MSPara1.pCamera = m_pCamera;
	MSPara1.pGeometry = (VSGeometry *)m_pSpatial;
	MSPara1.LightArray = m_Light;
	MSPara1.pMaterialInstance = m_pMaterialInstance;
	MSPara1.uiPassId = m_uiPassId;
	VSShaderKey::SetMaterialVShaderKey(&m_VShaderkey,MSPara1,GetPassType());
	if (m_pMaterialInstance->m_pCurVShader[GetPassType()] == NULL)
	{
		if (m_pVShaderSet)
		{
			unsigned int uiIndex = m_pVShaderSet->Find(m_VShaderkey);

			if (uiIndex != m_pVShaderSet->GetNum())
			{
				VSShader * pTemp = (*m_pVShaderSet)[uiIndex].Value;
				pVertexShader = (VSVShader *)(pTemp);
			}

		}

		if (pVertexShader == NULL)
		{
			pVertexShader = VSResourceManager::CreateVShader(MSPara1,GetPassType(),uiVShaderNum);
			if (!pVertexShader)
			{
				return 0;
			}
			if (m_pVShaderSet)
			{
				m_pVShaderSet->AddElement(m_VShaderkey,pVertexShader);
			}
		}
		m_pMaterialInstance->m_pCurVShader[GetPassType()] = pVertexShader;
	}
	else
	{
		if (m_pMaterialInstance->m_pCurVShader[GetPassType()]->m_ShaderKey == m_VShaderkey)
		{

		}
		else
		{
			if (m_pVShaderSet)
			{
				unsigned int uiIndex = m_pVShaderSet->Find(m_VShaderkey);

				if (uiIndex != m_pVShaderSet->GetNum())
				{
					VSShader * pTemp = (*m_pVShaderSet)[uiIndex].Value;
					pVertexShader = (VSVShader *)(pTemp);
				}
			}
			if (pVertexShader == NULL)
			{
				pVertexShader = VSResourceManager::CreateVShader(MSPara1,GetPassType(),uiVShaderNum);
				if (!pVertexShader)
				{
					return 0;
				}
				if (m_pVShaderSet)
				{
					m_pVShaderSet->AddElement(m_VShaderkey,pVertexShader);
				}
			}
			m_pMaterialInstance->m_pCurVShader[GetPassType()] = pVertexShader;
		}
	}
	if (!m_pVShaderSet)
	{
		VSResourceManager::GetVertexShaderMap().SetShader(VSUsedName::ms_cMaterialVertex,m_VShaderkey,pVertexShader);
		m_pVShaderSet = VSResourceManager::GetVertexShaderMap().GetShaderSet(VSUsedName::ms_cMaterialVertex);
	}
	return 1;
}
bool VSMaterialPass::GetPShader()
{
	VSMaterial * pMaterial = m_pMaterialInstance->GetMaterial();
	if (!pMaterial)
	{
		return 0;
	}
	VSPShader * pPixelShader = NULL;
	unsigned int uiPShaderNum = 0;

	if (!m_pPShaderSet)
	{
		m_pPShaderSet = VSResourceManager::GetMaterialShaderMap().GetShaderSet(pMaterial->GetResourceName());
	}
	else
	{
		uiPShaderNum = m_pPShaderSet->GetNum();
	}
	MaterialShaderPara1 MSPara1;
	MSPara1.pCamera = m_pCamera;
	MSPara1.pGeometry = (VSGeometry *)m_pSpatial;
	MSPara1.LightArray = m_Light;
	MSPara1.pMaterialInstance = m_pMaterialInstance;
	MSPara1.uiPassId = m_uiPassId;
	VSShaderKey::SetMaterialPShaderKey(&m_PShaderkey,MSPara1,GetPassType());
	if (m_pMaterialInstance->m_pCurPShader[GetPassType()] == NULL)
	{
		if (m_pPShaderSet)
		{
			unsigned int uiIndex = m_pPShaderSet->Find(m_PShaderkey);

			if (uiIndex != m_pPShaderSet->GetNum())
			{
				VSShader * pTemp = (*m_pPShaderSet)[uiIndex].Value;
				pPixelShader = (VSPShader *)(pTemp);
			}
		}

		if (pPixelShader == NULL)
		{
			pPixelShader = VSResourceManager::CreatePShader(MSPara1,GetPassType(),uiPShaderNum);
			if (!pPixelShader)
			{
				return 0;
			}
			if (m_pPShaderSet)
			{
				m_pPShaderSet->AddElement(m_PShaderkey,pPixelShader);
			}
		}
		m_pMaterialInstance->m_pCurPShader[GetPassType()] = pPixelShader;
	}
	else
	{
		if (m_pMaterialInstance->m_pCurPShader[GetPassType()]->m_ShaderKey == m_PShaderkey)
		{

		}
		else
		{
			if (m_pPShaderSet)
			{
				unsigned int uiIndex = m_pPShaderSet->Find(m_PShaderkey);

				if (uiIndex != m_pPShaderSet->GetNum())
				{
					VSShader * pTemp = (*m_pPShaderSet)[uiIndex].Value;
					pPixelShader = (VSPShader *)(pTemp);
				}
			}
			if (pPixelShader == NULL)
			{
				pPixelShader = VSResourceManager::CreatePShader(MSPara1,GetPassType(),uiPShaderNum);
				if (!pPixelShader)
				{
					return 0;
				}
				if (m_pPShaderSet)
				{
					m_pPShaderSet->AddElement(m_PShaderkey,pPixelShader);
				}
			}
			m_pMaterialInstance->m_pCurPShader[GetPassType()] = pPixelShader;
		}
	}

	if (!m_pPShaderSet)
	{
		VSResourceManager::GetMaterialShaderMap().SetShader(pMaterial->GetResourceName(),m_PShaderkey,pPixelShader);
		m_pPShaderSet = VSResourceManager::GetMaterialShaderMap().GetShaderSet(pMaterial->GetResourceName());
	}
	return 1;
}
